import { Injectable, ConflictException, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateUserDto } from '@/dto/create-user.dto';
import { UpdateUserDto } from '@/dto/update-user.dto';
import { User } from '@/entities/user.entity';
import { RedisService } from '@/services/redis.service';
import { LoggingService } from '@/services/logging.service';
import * as bcrypt from 'bcrypt';

@Injectable()
export class UsersService {
    constructor(
        @InjectRepository(User)
        private readonly userRepository: Repository<User>,
        private readonly redisService: RedisService,
        private readonly loggingService: LoggingService,
    ) {}

    async create(createUserDto: CreateUserDto): Promise<User> {
        // 检查邮箱是否已存在
        const existingUser = await this.userRepository.findOne({
            where: { email: createUserDto.email },
        });

        if (existingUser) {
            this.loggingService.app('创建用户失败：邮箱已存在', {
                email: createUserDto.email,
            });
            throw new ConflictException('邮箱已存在');
        }

        // 检查用户名是否已存在
        const existingUsername = await this.userRepository.findOne({
            where: { username: createUserDto.username },
        });

        if (existingUsername) {
            this.loggingService.app('创建用户失败：用户名已存在', {
                username: createUserDto.username,
            });
            throw new ConflictException('用户名已存在');
        }

        // 加密密码
        const hashedPassword = await bcrypt.hash(createUserDto.password, 10);

        // 创建用户
        const user = this.userRepository.create({
            ...createUserDto,
            password: hashedPassword,
        });

        const savedUser = await this.userRepository.save(user);

        // 清除缓存
        await this.redisService.del('users');

        this.loggingService.app('用户创建成功', {
            userId: savedUser.id,
            email: savedUser.email,
        });

        return savedUser;
    }

    async findAll(): Promise<User[]> {
        // 尝试从缓存获取
        const cachedUsers = await this.redisService.get('users');
        if (cachedUsers) {
            this.loggingService.app('从缓存获取用户列表');
            return cachedUsers;
        }

        // 从数据库获取
        const users = await this.userRepository.find({
            select: ['id', 'username', 'email', 'createdAt', 'updatedAt'],
        });

        // 设置缓存
        await this.redisService.set('users', users, 300); // 5分钟缓存

        this.loggingService.app('从数据库获取用户列表', {
            count: users.length,
        });

        return users;
    }

    async findOne(id: number): Promise<User> {
        // 尝试从缓存获取
        const cachedUser = await this.redisService.get(`user:${id}`);
        if (cachedUser) {
            this.loggingService.app('从缓存获取用户', { userId: id });
            return cachedUser;
        }

        // 从数据库获取
        const user = await this.userRepository.findOne({
            where: { id },
            select: ['id', 'username', 'email', 'createdAt', 'updatedAt'],
        });

        if (!user) {
            this.loggingService.app('用户不存在', { userId: id });
            throw new NotFoundException('用户不存在');
        }

        // 设置缓存
        await this.redisService.set(`user:${id}`, user, 300); // 5分钟缓存

        this.loggingService.app('从数据库获取用户', { userId: id });

        return user;
    }

    async findByEmail(email: string): Promise<User | null> {
        return await this.userRepository.findOne({
            where: { email },
        });
    }

    async update(id: number, updateUserDto: UpdateUserDto): Promise<User> {
        const user = await this.findOne(id);

        // 如果更新密码，需要重新加密
        if ('password' in updateUserDto && updateUserDto.password) {
            (updateUserDto as any).password = await bcrypt.hash(updateUserDto.password, 10);
        }

        // 更新用户
        Object.assign(user, updateUserDto);
        const updatedUser = await this.userRepository.save(user);

        // 清除相关缓存
        await this.redisService.del('users');
        await this.redisService.del(`user:${id}`);

        this.loggingService.app('用户更新成功', {
            userId: id,
            updatedFields: Object.keys(updateUserDto),
        });

        return updatedUser;
    }

    async remove(id: number): Promise<void> {
        const user = await this.findOne(id);
        await this.userRepository.remove(user);

        // 清除相关缓存
        await this.redisService.del('users');
        await this.redisService.del(`user:${id}`);

        this.loggingService.app('用户删除成功', { userId: id });
    }
}
